package cc.decat.escript.runtime;

import cc.decat.escript.builtin.ESLenBuiltinObject;
import cc.decat.escript.builtin.ESPrintBuiltinObject;
import cc.decat.escript.builtin.ESPrintlnBuiltinObject;
import cc.decat.escript.codegen.*;
import cc.decat.escript.object.ESConstObjects;
import cc.decat.escript.object.ESFunctionObject;
import cc.decat.escript.object.ESNormalFunctionObject;
import cc.decat.escript.object.ESObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// 全局上下文
public class GlobalContext {
    private final List<ESObject> constObjectList;
    private final ConstGenerate constGenerate;
    private final SymbolTable globalSymbolTable;
    private Env globalEnv;
    private FunctionGenerate globalFunctionGenerate;
    private ESFunctionObject globalFunctionObject;
    private final Map<String, ESObject> globalVarObjMap;

    public GlobalContext() {
        this.constObjectList = new ArrayList<>();
        this.constGenerate = new ConstGenerate(this.constObjectList);
        this.globalSymbolTable = new SymbolTable(new BlockGenerate(null));
        this.globalVarObjMap = new HashMap<>();
        initGlobalSymbolTable();
        initGlobalEnv();
    }

    private void initGlobalSymbolTable() {
        addGlobalVar("null", ESConstObjects.NULL);
        addGlobalVar("true", ESConstObjects.TRUE);
        addGlobalVar("false", ESConstObjects.FALSE);

        addGlobalVar("print", new ESPrintBuiltinObject());
        addGlobalVar("println", new ESPrintlnBuiltinObject());
        addGlobalVar("len", new ESLenBuiltinObject());
    }

    private void initGlobalEnv() {
        this.globalEnv = new Env(null, globalSymbolTable);
        for(LocalVarInfo localVarInfo : globalSymbolTable.getLocalVarInfoList()) {
            globalEnv.setLocalObj(localVarInfo.getIndex(), globalVarObjMap.get(localVarInfo.getName()));
        }
    }

    public void addGlobalVar(String name, ESObject val) {
        this.globalSymbolTable.findOrAddLocalVar(name);
        this.globalVarObjMap.put(name, val);
    }

    public List<ESObject> getConstObjectList() {
        return constObjectList;
    }

    public ConstGenerate getConstGenerate() {
        return constGenerate;
    }

    public SymbolTable getGlobalSymbolTable() {
        return globalSymbolTable;
    }

    public Env getGlobalEnv() {
        return globalEnv;
    }

    public void setGlobalFunctionObject(ESFunctionObject globalFunctionObject) {
        this.globalFunctionObject = globalFunctionObject;
    }

    public ESFunctionObject getGlobalFunctionObject() {
        return globalFunctionObject;
    }

    public FunctionGenerate getGlobalFunctionGenerate() {
        return globalFunctionGenerate;
    }

    public void setGlobalFunctionGenerate(FunctionGenerate globalFunctionGenerate) {
        this.globalFunctionGenerate = globalFunctionGenerate;
    }
}
